home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / DELPHI32 / SEARCH / RUBICON / WILDCARD.PAS < prev   
Pascal/Delphi Source File  |  1996-10-21  |  5KB  |  194 lines

  1. {************************************************************************
  2.  WildMatcher - a string matcher that understands * and ?
  3.  
  4.  Written 1/13/90, Kim Kokkonen, TurboPower Software
  5.  Updated 3/08/91 to allow specification of a dup trigger point (/n)
  6.  CompuServe ID [76004,2611]
  7.  Updated 7/28/94 to stand alone BP7 unit and
  8.  Updated 3/15/95 to Delphi class by Deven Hickingbotham, Tamarack Associates
  9. ************************************************************************}
  10.  
  11. {$R-,S-,I-,V-,B-,F-,G+}
  12. {$IFDEF Win32}
  13. {$LONGSTRINGS OFF}
  14. {$ENDIF}
  15.  
  16. unit WildCard;
  17.  
  18. interface
  19.  
  20. uses SysUtils;
  21.  
  22. const
  23.   EndChar = #255;        {Terminator to match strings}
  24.  
  25. type
  26.     TWildMatcher = class(TObject)
  27.       private
  28.       maAny  : Char;
  29.       maOne  : Char;
  30.       maCase : Boolean;       {True if case-sensitive matching}
  31.       maMask : String;   {Mask used for matching}
  32.       procedure SetAnyChar(Value : Char);
  33.       procedure SetMask(Value : String);
  34.       procedure SetOneChar(Value : Char);
  35.       public
  36.       constructor Create;
  37.         {-Create the mask string}
  38.       constructor Init(AMask : String ; ACaseSensitive : Boolean ; AAnyChar,AOneChar : Char);
  39.         {-Initialize the mask string}
  40.       function Matches(Name : String) : Boolean;
  41.         {-Return True if Name matches Mask}
  42.       function GetMask : String;
  43.         {-Return the simplified mask}
  44.       procedure SimplifyMask;
  45.         {-Used internally to simplify mask when object instantiated}
  46.       property AnyChar : Char read maAny write SetAnyChar;
  47.       property CaseSensitive : Boolean read maCase write maCase;
  48.       property Mask : String read maMask write SetMask;
  49.       property OneChar : Char read maOne write SetOneChar;
  50.     end;
  51.  
  52.     EWildCard = Class(Exception);
  53.  
  54. implementation
  55.  
  56. constructor TWildMatcher.Create;
  57. begin
  58.   inherited Create;
  59.   maAny := '*';
  60.   maOne := '?';
  61.   maCase := False;
  62.   maMask := '';
  63. end;
  64.  
  65. constructor TWildMatcher.Init(AMask : String ; ACaseSensitive : Boolean ;
  66.                               AAnyChar,AOneChar : Char);
  67. begin
  68.   inherited Create;
  69.   AnyChar := AAnyChar;
  70.   CaseSensitive := ACaseSensitive;
  71.   Mask := AMask;
  72.   OneChar := AOneChar;
  73. end;
  74.  
  75. procedure TWildMatcher.SetAnyChar(Value : Char);
  76. begin
  77.   if Value <> maOne then maAny := Value
  78.   else raise EWildCard.Create('AnyChar = OneChar')
  79. end;
  80.  
  81. procedure TWildMatcher.SetMask(Value : String);
  82. begin
  83.   if length(Value) >= 128 then
  84.     raise EWildCard.Create('Mask length too long')
  85.   else
  86.     if Value <> maMask THEN
  87.       begin
  88.         maMask := Value;
  89.         SimplifyMask;
  90.         maMask[Length(maMask)+1] := EndChar;
  91.       end
  92. end;
  93.  
  94. procedure TWildMatcher.SetOneChar(Value : Char);
  95. begin
  96.   if Value <> maAny then maOne := Value
  97.   else raise EWildCard.Create('AnyChar = OneChar')
  98. end;
  99.  
  100. function TWildMatcher.Matches(Name : String) : Boolean;
  101.   {-Return True if Name matches Mask}
  102. var
  103.   NLen : Byte absolute Name;
  104.   MPos : Word;
  105.   NPos : Word;
  106.   MPSave : Word;
  107.   NPSave : Word;
  108.   AnyOn : Boolean;
  109.   Ch : Char;
  110. begin
  111.   Matches := False;
  112.  
  113.   {Add terminator to input string}
  114.   Name[NLen+1] := EndChar;
  115.  
  116.   AnyOn := False;
  117.   MPos := 1;
  118.   NPos := 1;
  119.  
  120.   while (maMask[MPos] <> EndChar) or (Name[NPos] <> EndChar) do begin
  121.     {Look for '*'}
  122.     if maMask[MPos] = maAny then begin
  123.       if MPos >= Length(maMask) then begin
  124.         {Last character in maMask is '*', rest must match}
  125.         Matches := True;
  126.         Exit;
  127.       end;
  128.       AnyOn := True;
  129.       NPSave := NPos;
  130.       inc(MPos);
  131.       MPSave := MPos;
  132.     end;
  133.  
  134.     {Get next character from Name string}
  135.     if maCase then
  136.       Ch := Name[NPos]
  137.     else
  138.       Ch := UpCase(Name[NPos]);
  139.  
  140.     {Look for literal match}
  141.     if (Ch <> EndChar) and ((maMask[MPos] = maOne) or (maMask[MPos] = Ch))
  142.     then begin
  143.       {Matching character}
  144.       inc(MPos);
  145.       inc(NPos);
  146.     end else begin
  147.       {Mismatched character}
  148.       if not AnyOn or (NPSave >= Length(Name)) then
  149.         {Fatal mismatch, no '*' in effect or no way to advance past mismatch}
  150.         Exit;
  151.       {Increment restart point}
  152.       inc(NPSave);
  153.       {Try again at next Name position}
  154.       NPos := NPSave;
  155.       {Restart maMask just after the '*'}
  156.       MPos := MPSave;
  157.     end;
  158.   end;
  159.  
  160.   Matches := True;
  161. end;
  162.  
  163. function TWildMatcher.GetMask : String;
  164.   {-Return the simplified mask}
  165. begin
  166.   GetMask := maMask;
  167. end;
  168.  
  169. procedure TWildMatcher.SimplifyMask;
  170.   {-Used internally to simplify mask when object instantiated}
  171. var
  172.   MLen : Byte;
  173.   MPos : Word;
  174.   OMask : String;
  175.   OLen : Byte absolute OMask;
  176. begin
  177.   MLen := Length(maMask);
  178.   MPos := 1;
  179.   OLen := 0;
  180.   while MPos <= MLen do begin
  181.     if (MPos = 1) or (maMask[MPos] <> maAny) or (maMask[MPos-1] <> maAny) then begin
  182.       {Transfer maMask to OMask, skipping repeated asterisks}
  183.       inc(OLen);
  184.       OMask[OLen] := maMask[MPos];
  185.       if not maCase then
  186.         OMask[OLen] := UpCase(OMask[OLen]);
  187.     end;
  188.     inc(MPos);
  189.   end;
  190.   maMask := OMask;
  191. end;
  192.  
  193. end.
  194.